/*
 * Copyright 2023-2025, Haiku, Inc. All rights reserved.
 * Distributed under the terms of the MIT License.
 *
 * Authors:
 *   Haiku Development Team
 */

#include <boot/platform.h>
#include <boot/stage2.h>
#include <boot/stdio.h>
#include <kernel.h>

#include "efi_platform.h"
#include "arch_smp.h"

// 最大支持的CPU数量
#define MAX_CPUS 64

// CPU信息结构体
struct cpu_info {
    uint32 id;           // CPU ID
    uint32 apic_id;      // APIC ID
    uint32 package_id;   // 物理封装ID
    uint32 core_id;      // 核心ID
    uint32 smt_id;       // 超线程ID
    bool present;        // CPU是否存在
};

// 全局CPU信息数组
static cpu_info sCPUs[MAX_CPUS];
static uint32 sCPUCount = 0;

// 注册CPU
status_t
arch_smp_register_cpu(platform_cpu_info** info)
{
    if (sCPUCount >= MAX_CPUS)
        return B_ERROR;

    // 初始化新CPU信息
    cpu_info* cpu = &sCPUs[sCPUCount];
    memset(cpu, 0, sizeof(cpu_info));
    cpu->id = sCPUCount;
    cpu->present = true;

    // 更新CPU计数
    sCPUCount++;

    // 返回CPU信息指针
    if (info != NULL)
        *info = (platform_cpu_info*)cpu;

    return B_OK;
}

// 初始化SMP
status_t
arch_smp_init(void)
{
    // 确保至少有一个CPU
    if (sCPUCount == 0) {
        // 注册引导CPU
        arch_smp_register_cpu(NULL);
    }

    // 设置内核参数中的CPU计数
    gKernelArgs.num_cpus = sCPUCount;

    dprintf("Found %ld CPU%s\n", sCPUCount, sCPUCount == 1 ? "" : "s");

    // 复制CPU信息到内核参数
    for (uint32 i = 0; i < sCPUCount; i++) {
        cpu_info* cpu = &sCPUs[i];

        // 设置CPU拓扑信息
        gKernelArgs.arch_args.cpu_infos[i].id = cpu->id;
        gKernelArgs.arch_args.cpu_infos[i].package_id = cpu->package_id;
        gKernelArgs.arch_args.cpu_infos[i].core_id = cpu->core_id;
        gKernelArgs.arch_args.cpu_infos[i].smt_id = cpu->smt_id;

        dprintf("  CPU #%ld: package %ld, core %ld, smt %ld\n",
            cpu->id, cpu->package_id, cpu->core_id, cpu->smt_id);
    }

    return B_OK;
}

// 启动辅助CPU
status_t
arch_smp_boot_other_cpus(kernel_args* kernelArgs, addr_t entryPoint)
{
    // LoongArch64平台通常使用IPI (处理器间中断) 来启动辅助CPU
    // 在EFI引导阶段，我们通常不启动辅助CPU，而是留给内核完成
    // 这里只是设置必要的参数
    
    kernelArgs->arch_args.cpu_boot_entry = entryPoint;
    
    return B_OK;
}

// 获取当前CPU ID
int32
arch_smp_get_current_cpu(void)
{
    // 在引导阶段，我们假设只有引导CPU在运行
    return 0;
}

// 获取CPU计数
int32
arch_smp_get_num_cpus(void)
{
    return sCPUCount;
}